%option noyywrap nodefault yylineno case-insensitive

%{
#define YY_LTYPE_IS_TRIVIAL
#include <string>
#include <stdio.h>
#include "lp_defs.h"
#include "locations.h"
#include "recovery.h"
#include "../literalparsing/literals.h"
#include "../literalparsing/strings.h"



// Common return tokens
#define RET_TOK(TYPE) { save(yytext); return TYPE; }
//Suppress meaningless warnings from MSVC
#ifdef _MSC_VER
	#pragma warning( disable : 4996 273 102 )
#endif

//! Identifier temporary buffer
std::string * identifier;
//! State of a lexer work for merged tokens
LexerStateType    lexerstate;
extern const char * current_filename;
%}

%x IN_COMMENT
%x STRING
%x VERBATIM_STRING
%x ALIGNED_STRING
%x ESCAPED_CHARACTER
%x CHARACTER

CHAR_FORM1     (2_?((5_?[0-5])|[0-4]_?[0-9]))  
CHAR_FORM2     ([0-1]_?[0-9]_?[0-9])           
CHAR_FORM3     ([0-9]_?[0-9])                  
CHAR_FORM4     [0-9]                           
DEC_CHAR_FORMS ({CHAR_FORM1}|{CHAR_FORM2}|{CHAR_FORM3}|{CHAR_FORM4}) 
OCT_CHAR_FORMS (([0-3]_?[0-7]_?[0-7])|([0-7]_?[0-7])|([0-7]))
HEX_CHAR_FORMS ([0-9a-fA-F]_?[0-9a-fA-F]|[0-9a-fA-F])
BIN_CHAR_FORMS ([01]_?){1,8}
ALPHA          ([0-9][0-9_]*)


%%

%{
if (lexerstate==LST_RETURN_TWO_DOTS)
{
 lexerstate=LST_NORMAL;
 increment(2);
 return TWO_DOTS;
}
if (lexerstate==LST_RETURN_DOT)
{
 lexerstate=LST_RETURN_IDENTIFIER;
 increment(1);
 return '.';
}
if (lexerstate==LST_RETURN_IDENTIFIER)
{
  lexerstate=LST_NORMAL;
  increment(identifier->length());
  yylval.m_strg=identifier;
  return IDENTIFIER;
}
%}

<INITIAL>
{

":="                                          RET_TOK(ASSIGNMENT)
"/~"                                          RET_TOK(NTILDA)
"/="                                          RET_TOK(NEQ)
"//"                                          RET_TOK(TWO_BACKSLASHES)
\\\\                                          RET_TOK(TWO_SLASHES)
".."                                          RET_TOK(TWO_DOTS)
">="                                          RET_TOK(GEQ)
"<="                                          RET_TOK(LEQ)
"<<"                                          RET_TOK(LEFT_ARRAY)
">>"                                          RET_TOK(RIGHT_ARRAY)
elseif                                        RET_TOK(ELSEIF)
or                                            RET_TOK(OR)
true                                          {yylval.m_bool=true;save(yytext);return _BOOL;  }
false                                         {yylval.m_bool=false;save(yytext);return _BOOL; } 
from                                          RET_TOK(FROM)
loop                                          RET_TOK(LOOP)
until                                         RET_TOK(UNTIL)
when                                          RET_TOK(WHEN)
inspect                                       RET_TOK(INSPECT)
if                                            RET_TOK(IF)
select                                        RET_TOK(SELECT)
create                                        RET_TOK(CREATE)
undefine                                      RET_TOK(UNDEFINE)
redefine                                      RET_TOK(REDEFINE)
else                                          RET_TOK(ELSE)
then                                          RET_TOK(THEN)
local                                         RET_TOK(LOCAL)
do                                            RET_TOK(DO)
rename                                        RET_TOK(RENAME)
as                                            RET_TOK(AS)
inherit                                       RET_TOK(INHERIT)
not                                           RET_TOK(NOT)
and                                           RET_TOK(AND)
xor                                           RET_TOK(XOR)
and" "+then                                   RET_TOK(AND_THEN)
or" "+else                                    RET_TOK(OR_ELSE)
implies                                       RET_TOK(IMPLIES)
end                                           RET_TOK(END_DECL)
class                                         RET_TOK(CLASS)
deferred                                      RET_TOK(DEFERRED)
frozen                                        RET_TOK(FROZEN)
feature                                       RET_TOK(FEATURE)
convert                                       RET_TOK(CONVERT)
alias                                         RET_TOK(ALIAS)
";"|":"|","|"="|"("|")"|"["|"]"|"+"|"-"|"*"|"/"|"^"|"<"|">"|"?"|"!"|"."|"~"|"{"|"}"|"@"          RET_TOK(yytext[0])
[_a-zA-Z][_a-zA-Z0-9]*                        { yylval.m_strg=push_string(yytext); uppercase(*(yylval.m_strg));  save(yytext);  return IDENTIFIER; }
0[xX][0-9a-fA-F_]+                            { yylval.m_intl=parse_common(yytext,16); save(yytext); return INTEGER; }
0[cC][0-7_]+                                  { yylval.m_intl=parse_common(yytext+2,8); save(yytext); return INTEGER; }
0[bB][01_]+                                   { yylval.m_intl=parse_binary(yytext+2,yyleng); save(yytext); return INTEGER;}
[0-9][0-9_]*                                  { yylval.m_intl=parse_common(yytext,10); save(yytext); return INTEGER; }
[0-9][0-9_]*\.\.                              { 
                                                yytext[strlen(yytext)-2]=0; 
                                                increment(strlen(yytext));  
                                                yylval.m_intl=parse_common(yytext,10); 
                                                lexerstate=LST_RETURN_TWO_DOTS; 
                                                return INTEGER; 
                                              }
[0-9][0-9_]*\.[_a-zA-Z][_a-zA-Z0-9]*          { 
                                                char * dot=strchr(yytext,'.'); 
                                                *dot=0;
                                                save(yytext);
                                                identifier=push_string(dot+1);
                                                uppercase(*identifier);
                                                lexerstate=LST_RETURN_DOT;
                                                yylval.m_intl=parse_common(yytext,10);
                                                return INTEGER;
                                              }
(({ALPHA}\.)|(\.{ALPHA})|({ALPHA}\.{ALPHA}))([eE][+-]?{ALPHA})?     { yylval.m_real=parse_real(yytext); save(yytext); return REAL; }

\n|\r|\r\n|\n\r                             { save(); return INSTRUCTION_DELIMITER;   }
--                                          BEGIN(IN_COMMENT);
[ \t]                                       { save(yytext); }
<<EOF>>                                     { save(yytext);   return END_OF_FILE; }
\"\{(\n|\r|\r\n|\n\r)?                      { save(yytext); if (yytext[yyleng-1]=='\r' || yytext[yyleng-1]=='\n') compute(); yylval.m_strg=push_string("");BEGIN(VERBATIM_STRING);      }                      
\"\[(\n|\r|\r\n|\n\r)?                      { save(yytext); if (yytext[yyleng-1]=='\r' || yytext[yyleng-1]=='\n') compute(); ;yylval.m_strg=push_string("");BEGIN(ALIGNED_STRING);      }  
\"                                          { save(yytext); yylval.m_strg=push_string("");BEGIN(STRING);     }
\'                                          { save(yytext); yylval.m_strg=push_string(""); BEGIN(CHARACTER); }
[^ \n\r\t-]                                 { save(yytext); }
}

<IN_COMMENT> 
{
  [^\n\r]                                   { save(yytext); }
  <<EOF>>                                   { save(yytext);   return END_OF_FILE; }
  \n|\r|\r\n|\n\r                           { save(); BEGIN(INITIAL);}
}
<CHARACTER>
{
  [^%\'\n\r]                                { *(yylval.m_strg)+=std::string(yytext); compute(yytext); }
  \'                                        {  
											 compute(yytext); 
											 if (yylval.m_strg->size()>1) 
											 printf("Warning: multisymbol character literal at %d,%d\n",yylloc.last_line,yylloc.last_column); 
											 while(yylval.m_strg->size()!=1) 
												yylval.m_strg->erase(1,1); 
											 BEGIN(INITIAL); 
											 return _CHAR; 
											}
}
<STRING>
{
  [^%\"\n\r]+                               { *(yylval.m_strg)+=std::string(yytext); compute(yytext); }
  \"                                        {  compute(yytext); BEGIN(INITIAL); return STRING_LITERAL; }
}
<VERBATIM_STRING>
{
  [^%\"\n\r\}]+                             { *(yylval.m_strg)+=std::string(yytext); compute(yytext); }
  \n|\r|\r\n|\n\r                           {  yylval.m_strg->push_back('\n');compute(); }
  \}                                        { *(yylval.m_strg)+=std::string(yytext); compute(yytext); }
  \}\"                                      {  compute(yytext); BEGIN(INITIAL); return STRING_LITERAL; }
}
<ALIGNED_STRING>
{
 [^%\"\n\r\]]+                             { *(yylval.m_strg)+=std::string(yytext); compute(yytext); }
 \]\"                                      {  compute(yytext); BEGIN(INITIAL); if (strcmp(yylval.m_strg->c_str(),"")!=0) parse_aligned_string(*(yylval.m_strg)); else *(yylval.m_strg)="[]"; return STRING_LITERAL; }
 \]":="\"                                  {  compute(yytext); BEGIN(INITIAL); if (strcmp(yylval.m_strg->c_str(),"")==0)   *(yylval.m_strg)="[]:=";   else *(yylval.m_strg)+="]:=\"";  return STRING_LITERAL; }
 \]                                        { *(yylval.m_strg)+=std::string(yytext); compute(yytext); }
 \n|\r|\r\n|\n\r                           {  yylval.m_strg->push_back('\n');compute();}
}

<CHARACTER,STRING,VERBATIM_STRING,ALIGNED_STRING>
{
  %(\n|\r|\r\n|\n\r)                        { save(yytext);  }
  %A                                         { yylval.m_strg->push_back('@'); compute(yytext);  }
  %B                                         { yylval.m_strg->push_back('\x08'); compute(yytext);  }
  %C                                         { yylval.m_strg->push_back('^'); compute(yytext);  }
  %D                                         { yylval.m_strg->push_back('$'); compute(yytext);  }
  %F                                         { yylval.m_strg->push_back('\x0C'); compute(yytext);  }
  %H                                         { yylval.m_strg->push_back('/'); compute(yytext);  }
  %L                                         { yylval.m_strg->push_back('~'); compute(yytext);  }
  %N                                         { yylval.m_strg->push_back('\n'); compute(yytext);  }
  %Q                                         { yylval.m_strg->push_back('`'); compute(yytext);  }
  %R                                         { yylval.m_strg->push_back('\r'); compute(yytext);  }
  %S                                         { yylval.m_strg->push_back('#'); compute(yytext);  }
  %T                                         { yylval.m_strg->push_back('\t'); compute(yytext);  }
  %U                                         { yylval.m_strg->push_back('\0'); compute(yytext);  }
  %V                                         { yylval.m_strg->push_back('|'); compute(yytext);  }
  "%%"                                       { yylval.m_strg->push_back('%'); compute(yytext);  }
  %'                                         { yylval.m_strg->push_back('\''); compute(yytext);  }
  %\"                                        { yylval.m_strg->push_back('\"'); compute(yytext);  } 
  %\(                                        { yylval.m_strg->push_back('['); compute(yytext);  } 
  %\)                                        { yylval.m_strg->push_back(']'); compute(yytext);  } 
  %\<                                        { yylval.m_strg->push_back('{'); compute(yytext);  } 
  %\>                                        { yylval.m_strg->push_back('}'); compute(yytext);  } 
  %\/({DEC_CHAR_FORMS})\/    { std::string cfk=yytext+1;  cfk.erase(cfk.end()-1); compute(yytext); char c=(char)parse_common(cfk.c_str(),10); yylval.m_strg->push_back(c);    } 
  %\/0[cC]{OCT_CHAR_FORMS}\/ { std::string cfk=yytext+3;  cfk.erase(cfk.end()-1); compute(yytext); char c=(char)parse_common(cfk.c_str(),8); yylval.m_strg->push_back(c);    }
  %\/0[xX]{HEX_CHAR_FORMS}\/ { std::string cfk=yytext+3;  cfk.erase(cfk.end()-1); compute(yytext); char c=(char)parse_common(cfk.c_str(),16); yylval.m_strg->push_back(c);    }
  %\/0[bB]{BIN_CHAR_FORMS}\/ { std::string cfk=yytext+3;  cfk.erase(cfk.end()-1); compute(yytext); char c=(char)parse_common(cfk.c_str(),2); yylval.m_strg->push_back(c);    }
  %.                                         { printf("Unknown escaped character %c in  string literal (%d,%d) ",yytext[0],yylloc.last_line,yylloc.last_column); compute(yytext); yylval.m_strg->push_back('%');yylval.m_strg->push_back(yytext[0]);   }
}
%%
